
var imgWidth = 212, imgHeight = 132;
var imgWidthSmall = 150, imgHeightSmall = 93;
var sitesPerLine = 4;


try {
	const Cc = Components.classes;
	const Ci = Components.interfaces;
	Components.utils.import('resource://superstart/xl.js');
	var SuperStart = getMainWindow().SuperStart;
	var getString = SuperStart.getString;
	var logger = Cc['@mozilla.org/consoleservice;1'].getService(Ci.nsIConsoleService);
	var ssObj = Cc['@enjoyfreeware.org/superstart;1'];
	var ob = ssObj.getService(Ci.ssIObserverable);
	var cfg = ssObj.getService(Ci.ssIConfig);
	var sm = ssObj.getService(Ci.ssISiteManager);
	var td = ssObj.getService(Ci.ssITodoList);
	var tm = ssObj.getService(Ci.ssIThemes);
	sitesPerLine = cfg.getConfig('site-perline');
} catch (e) {
	if (logger != null) {
		logger.logStringMessage(e);
	} else {
		logger = {
			logStringMessage: function() {}
		};
	}

	sm = {};
}

var pageLoaded = false;
window.addEventListener('DOMContentLoaded', function() {
	window.removeEventListener('DOMContentLoaded', arguments.callee, false);
	initializeThemes();
}, false);

window.addEventListener('load', function() {
	window.removeEventListener('load', arguments.callee, false);
	sU.removeClass($('container'), 'hidden');
	registerEvents();
	initialize();

	pageLoaded = true;
	layout();
}, false);

window.addEventListener('unload', function() {
	window.removeEventListener('unload', arguments.callee, false);
	window.removeEventListener('resize', onResize, false);

	unregisterEvents();
}, false);

window.addEventListener('resize', onResize, false);

function onResize() {
	layout();
}

function registerEvents() {
	registerSiteEvents();
	registerTodoEvents();
}

function unregisterEvents() {
	unregisterSiteEvents();
	unregisterTodoEvents();
}

function initialize() {
	initializeTopToolbar();
	initializeSites();
	initializeTodo();
}



////////////////////////////////////////////////////////////
// top bar
function initializeTopToolbar() {
	var ToolbarButton = function(id, popupid, strid, cfgEvt, cfgKey) {
		var that = this;
		var elem = $(id);
		if (elem == null) {
			return;
		}

		function show() {
			sU.removeClass(elem, 'hidden');
		}

		function hide() {
			sU.addClass(elem, 'hidden');
		}

		function onEvtChanged(cfgevt, value) {
			if (value) {
				show();
			} else {
				hide();
			}
		}

		function onMouseDown(evt) {
			if (evt.button != 0) {
				return;
			}
		
			function onPopupHiding(evtHiding) {
				var popup = evtHiding.target;
				if (popup.id != popupid) {
					return;
				}
				window.setTimeout(function() {
					sU.removeClass(elem, 'opened');
					var popup = win.document.getElementById(popupid);
					popup.removeEventListener('popuphiding', onPopupHiding, true);
				}, 0);
			}
		
			var win = getMainWindow();
			var popup = win.document.getElementById(popupid);
			if (popup) {
				if (popup.state == 'closed') {
					var obj = win.document.getElementById('browser').boxObject;
					var pos = sU.getPosition(elem), margin = sU.getElementMargin(elem), border = sU.getElementBorder(elem), padding = sU.getElementPadding(elem), dimension = sU.getElementDimension(elem);
					var x = pos[0] + obj.screenX, y = pos[1] + obj.screenY;
					y += dimension[1] + margin[0] + margin[2] + border[0] + border[2] + padding[0] + padding[2];
					y += 5;
					popup.openPopupAtScreen(x, y, false);
					sU.addClass(elem, 'opened');
					popup.addEventListener('popuphiding', onPopupHiding, true);
				} else {
					popup.hidePopup();
				}
			}
		}

		elem._tlButton = this;
		elem.innerHTML = getString(strid);
		elem.addEventListener('mousedown', onMouseDown, false);
		ob.subscribe(cfgEvt, onEvtChanged);
		window.addEventListener('unload', function() {
			window.removeEventListener('unload', arguments.callee, false);
			ob.unsubscribe(cfgEvt, onEvtChanged);
			elem._tlButton = null;
			delete elem._tlButton;
			elem = null;
		}, false);

		if (cfg.getConfig(cfgKey)) {
			show();
		}
	}

	var maps = [
		['top-toolbar-bookmark', 'superstart-bookmarks', 'ssBookmark', 'toolbar-bookmark', 'toolbar-bookmark'],
		['top-toolbar-recently-closed', 'superstart-recently-closed-list', 'ssRecentlyClosed', 'toolbar-recentlyclosed', 'toolbar-recentlyclosed'],
	];

	for (var i = 0, l = maps.length; i < l; ++ i) {
		var m = maps[i];
		var t = new ToolbarButton(m[0], m[1], m[2], m[3], m[4]);
	}
}

// themes
function initializeThemes() {
	refresh();
	function insertStyle(id, href) {
		var style = document.createElement('link');
		style.id = id;
		style.setAttribute('rel', 'stylesheet');
		style.setAttribute('type', 'text/css');
		style.setAttribute('href', href);
		document.getElementsByTagName('head')[0].appendChild(style);
	}

	function refresh() {
		try {
			var currTheme = cfg.getConfig('theme');
			var themes = JSON.parse(tm.getThemes());
			var theme = JSON.parse(tm.getTheme(currTheme));

			// 1. theme & customize
			['theme', 'customize'].forEach(function(id, i, a) {
				var style = $(id);
				if (style) {
					style.parentNode.removeChild(style);
					style = null;
				}
			});
			if (theme.css != '') {
				insertStyle('theme', theme.css);
			}
			if (cfg.getConfig('use-customize')) {
				insertStyle('customize', tm.getUsUrl());
			}

			// 2. buttons
			var themeSelector = $('theme-selector');
			while (themeSelector.firstChild) {
				themeSelector.removeChild(themeSelector.firstChild);
			}

			if (cfg.getConfig('toolbar-themes')) {
				for (var i = 0, l = themes.length; i < l; ++ i) {
					var t = themes[i];
					var thumbnail = t['thumbnail-background'];
					if (thumbnail != undefined) {
						var li = document.createElement('li');
						li.theme = t;
						li.onclick = onClick;
						li.setAttribute('title', t.name);
						li.style.background = thumbnail;
						if (t.name == currTheme) {
							sU.addClass(li, 'current');
						}
						themeSelector.appendChild(li);
					}
				}
			}

			if (pageLoaded) {
				window.setTimeout(function() {
					layout();
				}, 0);
			}
		} catch (e) {
			logger.logStringMessage(e);
		}
	}

	ob.subscribe('theme', onThemeChanged);
	ob.subscribe('toolbar-themes', onToolbarThemes);
	ob.subscribe('theme-loaded', onThemeLoaded);
	ob.subscribe('theme-removed', onThemeRemoved);
	ob.subscribe('use-customize', onUseCustomize);
	ob.subscribe('user-style-changed', onUserStyleChanged);
	window.addEventListener('unload', function() {
		window.removeEventListener('unload', arguments.callee, false);

		ob.unsubscribe('theme', onThemeChanged);
		ob.unsubscribe('toolbar-themes', onToolbarThemes);
		ob.unsubscribe('theme-loaded', onThemeLoaded);
		ob.unsubscribe('theme-removed', onThemeRemoved);
		ob.unsubscribe('use-customize', onUseCustomize);
		ob.unsubscribe('user-style-changed', onUserStyleChanged);
	}, false);

	function onThemeChanged(evt, newTheme) {
		refresh();
	}

	function onToolbarThemes(evt, showThemes) {
		refresh();
	}

	function onThemeLoaded(evt, themeName) {
		refresh();
	}

	function onThemeRemoved(evt, themeName) {
		refresh();
	}

	function onUseCustomize(evt, use) {
		var style = $('customize');
		if (style) {
			style.parentNode.removeChild(style);
			style = null;
		}
		if (cfg.getConfig('use-customize')) {
			insertStyle('customize', tm.getUsUrl());
		}
	}

	function onUserStyleChanged(evt, url) {
		// window.setTimeout(function() {
			document.location.reload();
		// }, 0);
	}

	function onClick(evt) {
		var li = evt.target;
		if (!sU.hasClass(li, 'current')) {
			var t = li.theme;
			if (t != undefined) {
				cfg.setConfig('theme', t.name);
			}
		}
	}
}




////////////////////////////////////////////////////////////
// sites
function initializeSites() {
	onEvtSiteCompact('site-compact', cfg.getConfig('site-compact'));
	onEvtShowFavicon('show-favicon', cfg.getConfig('show-favicon'));
	onEvtShowBlank('show-blank', cfg.getConfig('show-blank'));

	var sites = sm.getSites();
	for (var i = 0, l = sites.length; i < l; ++ i) {
		insertSite(i, sites[i]);
	}

	updateSiteTitle();

	$('compact-switch-container').onclick = function() {
		var panel = $('site-panel');
		if (sU.hasClass(panel, 'compact')) {
			cfg.setConfig('site-compact', false);
		} else {
			cfg.setConfig('site-compact', true);
		}
	}


	document.addEventListener('mousedown', onMouseButtonDown, true);
	document.addEventListener('mouseup', onMouseButtonUp, false);
	document.addEventListener('mousemove', onMouseMove, false);
	document.addEventListener('click', onClick, false);
	document.addEventListener('contextmenu', onContextMenu, false);
}

function layout() {
	if (!pageLoaded) {
		return;
	}
	try {
		document.body.style.height = window.innerHeight + 'px';
		var fitIfPossible = cfg.getConfig('fit-height-if-possible');
		var isCompact = cfg.getConfig('site-compact');
		var contain = false;
		var clientWidth = document.body.clientWidth;
		var imageWidth = imgWidth;
		var imageHeight = imgHeight;
		var minHeight = 54;
		var minWidth = Math.floor(212 * minHeight / 132);
	
		var todoPanel = $('todo-panel');
		var sitePanel = $('site-panel');
	
		var todoWidth = sU.getCSSRule('#todo-panel', 'width').replace(/px/, '') - 0;
		if (sU.hasClass(todoPanel, 'hide')) {
			var todoSwitch = $('todo-switch');
			todoWidth = todoSwitch.scrollWidth;
		}
	
		// get the margin, border
		var site = document.querySelector('.site');
		var margin = sU.getElementMargin(site);
		margin = margin[1] + margin[3];
	
		var snapshot = site.querySelector('.snapshot');
		var border = sU.getElementBorder(snapshot);
		border = border[1] + border[3];

		var spMargin = sU.getElementMargin(sitePanel);
		var spPadding = sU.getElementPadding(sitePanel);
		var siteEx = spMargin[1] + spMargin[3] + spPadding[1] + spPadding[3];

		var tdMargin = sU.getElementMargin(todoPanel);
		var tdPadding = sU.getElementPadding(todoPanel);
		var tdEx = tdMargin[1] + tdMargin[3] + tdPadding[1] + tdPadding[3];

	
		var siteWidth = (imageWidth + margin + border) * sitesPerLine;
		if (siteWidth + siteEx + todoWidth + tdEx > clientWidth) {
			imageWidth = imgWidthSmall;
			imageHeight = imgHeightSmall;
			siteWidth = (imageWidth + margin + border) * sitesPerLine;

			// fit in compact
			if (siteWidth + siteEx + todoWidth + tdEx > clientWidth && isCompact) {
				siteWidth = clientWidth - siteEx - todoWidth - tdEx;
				imageWidth = Math.floor(siteWidth / sitesPerLine) - margin - border;
				if (imageWidth < minWidth) {
					imageWidth = minWidth;
				}
				imageHeight = Math.floor(132 * imageWidth / 212);
				siteWidth = (imageWidth + margin + border) * sitesPerLine;
			}
		}
	
		// fit if possible
		if (fitIfPossible && !isCompact) {
			var avaHeight = document.body.clientHeight;
			avaHeight -= sU.getElementFullHeight($('top-panel'));
			avaHeight -= sU.getElementFullHeight($('compact-switch-container'));
			var sites = sitePanel.querySelectorAll('.site');
			if (sites.length > 0) {
				var s = sites[0];
				var shot = s.querySelector('.snapshot');
				var desc = s.querySelector('.desc');
				var sh = sU.getElementExtensionalY(s);
				if (shot) {
					sh += sU.getElementExtensionalY(shot);
				}
				if (desc) {
					sh += sU.getElementFullHeight(desc);
				}
				var lines = sites.length / sitesPerLine;
				var heightTmp = Math.floor(avaHeight / lines);
				if (heightTmp < sh + imageHeight) {
					imageHeight = heightTmp - sh;
					if (imageHeight < minHeight) {
						imageHeight = minHeight;
					}
					imageWidth = Math.floor(212 * imageHeight / 132);
					siteWidth = (imageWidth + margin + border) * sitesPerLine;
					contain = true;
				}
			}
		}

		// set panels
		sitePanel.style.width = siteWidth + 'px';
		var x = (clientWidth - siteWidth - todoWidth - siteEx - tdEx) / 2;
		x = x < 0 ? 0 : x;
		sitePanel.style.left = x + 'px';
		x += siteWidth + siteEx;
		todoPanel.style.left = x + 'px';
		todoPanel.style.width = todoWidth + 'px';

	
		// images
		var imgs = sitePanel.getElementsByClassName('snapshot');
		[].forEach.call(imgs, function(img) {
			var style = img.style;
			style.width = imageWidth + 'px';
			style.height = imageHeight + 'px';
			if (!sU.hasClass(img, 'empty')) {
				if (contain) {
					style.MozBackgroundSize = style.backgroundSize = 'contain';
				} else {
					style.MozBackgroundSize = style.backgroundSize = imageWidth + 'px ' + imageHeight + 'px';
				}
			}
		});
	
		// <p>
		var pWidth = imageWidth + border;
		var ps = sitePanel.getElementsByClassName('desc');
		[].forEach.call(ps, function(p) {
			p.style.width = pWidth + 'px';
		});
	} catch (e) {
	}
}

var tmplSite = '<a href="%url%" title="%title%">' +
          	'<div class="toolbar"><div class="tb-bg">' +
			'<div class="button remove" onclick="return onSiteRemove(this);" title="' +
				getString('ssSiteRemove') + '"></div>' +
			'<div class="button refresh" onclick="return onSiteRefresh(this);" title="' +
				getString('ssSiteRefresh') + '"></div>' +
			'<div class="button setting" onclick="return onSiteSetting(this);" title="' +
				getString('ssSiteSetting') + '"></div>' +
			'<div class="button newtab" onclick="return onSiteNewTab(this);" title="' +
				getString('ssSiteOpenInNewTab') + '"></div>' +
		'</div></div>' +
           	'<div class="snapshot" style="background-image:url(\'%bgImage%\');"></div>' +
           	'<p class="desc">' +
           		'<img src="moz-anno:favicon:%icon%" class="favicon" />' +
           		'<span>%displayName%</span>' +
                '</p>' +
           '</a>';
var tmplSiteEmpty = '<div class="snapshot empty" onclick="onSiteSetting(this);"></div>' +
                '<p class="desc">&nbsp;</p>';
var hovers = ['hover1', 'hover2', 'hover3', 'hover4', 'hover5', 'hover6', 'hover7', 'hover', 'hover'];
var hoverStr = hovers.join(' ');
function insertSite(index, site) {
	var panel = $('site-panel');
	var id = 'site-' + index;
	var elem = document.createElement('div');
	elem.id = id;
	elem.className = 'site';
	panel.appendChild(elem);

	updateSite(elem, site);

	// mouse over / out
	elem.addEventListener('mouseover', function(evt) {
		if (!sU.isChild(evt.relatedTarget, this)) {
			sU.removeClass(this, hoverStr);
			var that = this;
			this.hoverTimeout = window.setTimeout(function() {
				var idx = -1;
				for (var i = 0; i < hovers.length; ++ i) {
					if (sU.hasClass(that, hovers[i])) {
						idx = i;
						break;
					}
				}
				if (idx != -1) {
					sU.removeClass(that, hovers[idx]);
				}
				++ idx;
				sU.addClass(that, hovers[idx]);
				if (hovers[idx] != 'hover') {
					that.hoverTimeout = window.setTimeout(arguments.callee, 40);
				} else {
					that.hoverTimeout = undefined;
				}
			}, 40);
		}
	}, false);

	elem.addEventListener('mouseout', function(evt) {
		if (!sU.isChild(evt.relatedTarget, this)) {
			if (this.hoverTimeout) {
				window.clearTimeout(this.hoverTimeout);
				this.hoverTimeout = undefined;
			}
			sU.removeClass(this, hoverStr);
		}
	}, false);
}

function updateSite(elem, site) {
	while (elem.children.length > 0) {
		elem.removeChild(elem.children[0]);
	}

	if (site.url == null) {
		elem.innerHTML = tmplSiteEmpty;
	} else {
		site['bgImage'] = site['image'] || site['snapshot'];
		for (var k in site) {
			site[k] = sU.escapeHTML(site[k]);
		}
		elem.innerHTML = xl.utils.template(tmplSite, site, false);
	}
}

function updateSiteTitle() {
	var sites = sm.getSites();
	var nonEmpty = 0;
	for (var i = 0, l = sites.length; i < l; ++ i) {
		if (sites[i].url != null) {
			nonEmpty ++;
		}
	}
	$('site-title').innerHTML = getString('ssSiteTitle') + ' (' + nonEmpty + '/' + sites.length + ')';
}


////////////////////////////////////////////////////////////////////////////////
// click handlers

function getSiteIndexFromElement(target) {
	var index = -1;
	while(target != document) {
		if (sU.hasClass(target, 'site')) {
			index = target.id;
			index = index.replace(/site-/, '') - 0;
			break;
		}
		target = target.parentNode;
	}
	return index;
}

function onSiteRefresh(elem) {
	var index = getSiteIndexFromElement(elem);
	if (index != -1) {
		sm.refreshSite(index);
	}
	return false;
}

function onSiteSetting(elem) {
	var index = getSiteIndexFromElement(elem);
	if (index != -1) {
		openUrlDialog(index);
	}
	return false;
}

function onSiteRemove(elem) {
	var index = getSiteIndexFromElement(elem);
	if (index != -1) {
		var site = sm.getSite(index);
		var str = getString('ssSiteRemovePrompt');
		str = xl.utils.template(str, site);
		if (confirm(str)) {
			sm.removeSite(index);
		}
	}
	return false;
}

function onSiteNewTab(elem) {
	var index = getSiteIndexFromElement(elem);
	if (index != -1) {
		var site = sm.getSite(index);
		if (site.url != null) {
			getMainWindow().getBrowser().addTab(site.url);
		}
	}
	return false;
}

var urlDialogs = {};
function openUrlDialog(index) {
	if (urlDialogs[index] != null) {
		urlDialogs[index].focus();
	} else {
		var dlg = window.openDialog('chrome://superstart/content/url.xul',
			'',
			'chrome,dialog,dependent=yes,centerscreen=yes,resizable=yes', index, urlDialogs);
		urlDialogs[index] = dlg;
	}
}

////////////////////////////////////////////////////////////////////////////////
// drag handlers
var draged = null;
function onMouseButtonDown(evt) {

	if (evt.button != 0) {
		return;
	}

	if (draged != null) {
		var img = draged.elem;
		if (img) {
			img.parentNode.removeChild(img);
		}
		draged = null;
	}

	var target = evt.target;
	if (sU.hasClass(target, 'snapshot') || sU.hasClass(target, 'toolbar')) {
		var index = getSiteIndexFromElement(target);
		if (index != -1) {
			var site = sm.getSite(index);
			if (site.url == null) {
				return;
			}

			draged = {
				'index': index,
				'site': site,
				'x': evt.clientX,
				'y': evt.clientY,
			};

			evt.preventDefault();
			document.defaultView.focus(); // make the content focus
		}
	}
}

function onMouseButtonUp(evt) {
	if (evt.button != 0) {
		return;
	}

	if (draged != null) {
		// some cleanup
		if (draged['hover']) {
			sU.removeClass(draged['hover'], 'hover');
		}
		var panel = $('site-panel');
		sU.removeClass(panel, 'draging');

		var img = draged['elem'];
		if (img) {
			img.parentNode.removeChild(img);
			var index = draged.index;
			draged = null;

			if (evt.clientY < 0 || evt.clientY > document.documentElement.clientHeight || evt.clientX < 0 || evt.clientX > document.documentElement.clientWidth) {
				return;
			}

			// test is in any snapshot
			var sites = sm.getSites();
			for (var i = 0, l = sites.length; i < l; ++ i) {
				var site = sites[i];

				var siteElem = $('site-' + i);
				var snapshot = siteElem.querySelector('.snapshot');
				if (sU.isPointInElement(snapshot, evt.clientX, evt.clientY)) {
					if (index != i) {
						sm.exchangeSite(index, i);
					}
					break;
				}
			}

		} else {
			var site = draged.site;
			draged = null;
			if (evt.ctrlKey) {
				try {
					getMainWindow().getBrowser().addTab(site.url);
				} catch (e) {
					document.location.href = site.url;
				}
			} else {
				document.location.href = site.url;
			}
		}
	}
}

function onMouseMove(evt) {
	if (draged != null) {
		if (draged['elem'] == null) {
			if (Math.abs(evt.clientX - draged['x']) > 10 ||
			    Math.abs(evt.clientY - draged['y']) > 10) {
				// begin drag
				var img = document.createElement('img');
				img.className = 'dragbox';
				img.src = draged.site.image || draged.site.snapshot;
				img.style.left = (evt.clientX - 75 + window.scrollX) + 'px';
				img.style.top = (evt.clientY - 46 + window.scrollY) + 'px';

				var p = document.body;
				p.appendChild(img);

				draged['elem'] = img;
				draged['scrollMaxY'] = window.scrollMaxY;

				var panel = $('site-panel');
				sU.addClass(panel, 'draging');
			}
		} else { // in drag
			var img = draged['elem'];
			img.style.left = (evt.clientX - 75 + window.scrollX) + 'px';
			img.style.top = (evt.clientY - 46 + window.scrollY) + 'px';

			var cx = evt.clientX, cy = evt.clientY;
			draged['cursor'] = {x: cx, y: cy};
			if (cy < 0 || cy > document.documentElement.clientHeight) {
				if (draged['timing'] == undefined) {
					draged['timing'] = true;
					window.setTimeout(onScrollScreenTimer, 0);
				}
			}

			// set the 'hover'
			if (draged['snapshots'] == undefined) {
				draged['snapshots'] = document.getElementsByClassName('snapshot');
			}
			var snapshots = draged.snapshots;
			var hover = undefined;
			for (var i = 0, l = snapshots.length; i < l; ++ i) {
				var snapshot = snapshots[i];
				if (sU.isPointInElement(snapshot, cx, cy)) {
					hover = snapshot;
					break;
				}
			}
			if (draged['hover'] !== hover) {
				if (draged['hover'] != undefined) {
					sU.removeClass(draged['hover'], 'hover');
				}
				draged['hover'] = hover;
				sU.addClass(hover, 'hover');
			}
		}
	}
}

/* when the cursor is off screen, scroll the page in timer */
function onScrollScreenTimer() {
	delete draged['timing'];
	if (draged['cursor'] == undefined) {
		return;
	}

	var cx = draged.cursor.x, cy = draged.cursor.y;
	var goon = false;
	if (cy < 0 && window.scrollY > 0) {
		window.scrollByLines(-1);
		goon = true;
	} else if (cy > document.documentElement.clientHeight){
		var offset = draged['scrollMaxY'] - window.scrollY;
		offset = offset > 20 ? 20 : offset;
		if (offset > 0) {
			window.scrollBy(0, offset);
			goon = true;
		}
	}

	if (goon) {
		draged['timing'] = true;
		window.setTimeout(arguments.callee, 50);

		var img = draged['elem'];
		if (img) {
			img.style.left = (cx - 75 + window.scrollX) + 'px';
			img.style.top = (cy - 46 + window.scrollY) + 'px';
		}
	}
}

function onClick(evt) {
	if (evt.button != 0) {
		return;
	}
	var target = evt.target;
	if (sU.hasClass(target, 'snapshot')) {
		evt.preventDefault();
	}
}

function onContextMenu(evt) {
	if (evt.target.id == 'todo-input') {
		return;
	}
	var win = getMainWindow();
	var menu = win.document.getElementById('superstart-menu');
	if (menu) {
		menu.openPopupAtScreen(evt.screenX, evt.screenY, true);
		evt.preventDefault();
	}
}

////////////////////////////////////////////////////////////////////////////////
// event handlers

var siteEventMap = {
	'site-added' : onEvtSiteAdded,
	'site-updated' : onEvtSiteUpdated,
	'site-removed' : onEvtSiteRemoved,
	'site-compact' : onEvtSiteCompact,
	'sites-reloaded' : onEvtSitesReloaded,
	'show-favicon' : onEvtShowFavicon,
	'show-blank' : onEvtShowBlank,
	'fit-height-if-possible' : onEvtFitIfPossible,
};

function registerSiteEvents() {
	try {
		for (var k in siteEventMap) {
			ob.subscribe(k, siteEventMap[k]);
		}
	} catch (e) {
		logger.logStringMessage('*** ' + e + ' ***');
	}
}

function unregisterSiteEvents() {
	try {
		for (var k in siteEventMap) {
			ob.unsubscribe(k, siteEventMap[k]);
		}
	} catch (e) {
		logger.logStringMessage('*** ' + e + ' ***');
	}
}

function onEvtSiteAdded(evt, indexes) {
	for (var i = 0, l = indexes.length; i < l; ++ i) {
		var index = indexes[i];
		var site = sm.getSite(index);
		var elem = $('site-' + index);
		if (elem) {
			updateSite(elem, site);
		} else {
			insertSite(index, site);
		}
	}
	updateSiteTitle();
	layout();
}

function onEvtSiteUpdated(evt, indexes) {
	for (var i = 0, l = indexes.length; i < l; ++ i) {
		var index = indexes[i];
		var elem = $('site-' + index);
		if (elem) {
			var site = sm.getSite(index);
			updateSite(elem, site);
		} else {
			document.location.reload();
			return;
		}
	}
	updateSiteTitle();
	layout();
}

function onEvtSiteRemoved(evt, indexes) {
	for (var i = 0, l = indexes.length; i < l; ++ i) {
		var index = indexes[i];
		var elem = $('site-' + index);
		if (elem) {
			elem.parentNode.removeChild(elem);
		}
	}
	updateSiteTitle();
}

function onEvtSiteCompact(evt, isCompact) {
	var panel = $('site-panel');
	if (isCompact) {
		sU.addClass(panel, 'compact');
	} else {
		sU.removeClass(panel, 'compact');
	}
	layout();
}

function onEvtFitIfPossible(evt, fit) {
	if (!cfg.getConfig('site-compact')) {
		layout();
	}
}

function onEvtShowFavicon(evt, showFavicon) {
	var panel = $('site-panel');
	if (showFavicon) {
		sU.removeClass(panel, 'hidefavicon');
	} else {
		sU.addClass(panel, 'hidefavicon');
	}
}

function onEvtShowBlank(evt, showBlank) {
	var panel = $('site-panel');
	if (showBlank) {
		sU.removeClass(panel, 'hideblank');
	} else {
		sU.addClass(panel, 'hideblank');
	}
}

function onEvtSitesReloaded(evt, dummy) {
	document.location.reload();
}

////////////////////////////////////////////////////////////
// todo
var tmplTodo = '<div class="toolbar">' +
                '<div class="button %star%" onclick="return onTodoButtonStar(this);"></div>' +
               	'<div class="button done" onclick="return onTodoButtonDone(this);" title="' +
               	getString('ssTodoDone') + '"></div>' +
               '</div><p class="%type%">%text%</p>';
var todoAddStar = getString('ssTodoAddStar');
var todoRemoveStar = getString('ssTodoRemoveStar');
function initializeTodo() {
	var input = $('todo-input');
	input.setAttribute('placeholder', getString('ssTodoPlaceHolder'));

	input.addEventListener('keypress', function(evt) {
		if (evt.keyCode == 13) { // return
			evt.preventDefault();
			var text = input.value;
			if (text != '') {
				input.value = '';
				td.addTodo('normal', text, 0);
			}
		}
	}, false);
	input.addEventListener('focus', function(evt) {
		sU.removeClass(input, 'init');
	}, false);
	input.addEventListener('blur', function(evt) {
		if (input.value == '') {
			sU.addClass(input, 'init');
		}
	}, false);

	var todoSwitch = $('todo-switch');
	todoSwitch.addEventListener('click', function() {
		cfg.setConfig('todo-hide', !cfg.getConfig('todo-hide'));
	}, false);
	onEvtTodoHide('todo-hide', cfg.getConfig('todo-hide'));

	var todoList = td.getTodoList();
	for (var i = 0, l = todoList.length; i < l; ++ i) {
		insertTodo(todoList[i]);
	}
}

function insertTodo(todo) {
	var list = $('todo-list');
	var li = document.createElement('li');
	updateTodo(li, todo);
	list.appendChild(li);
}

function updateTodo(li, todo) {
	todo.text = sU.escapeHTML(todo.text);
	todo.star = (todo.priority || 0) ? 'star' : 'nostar';
	li.innerHTML = xl.utils.template(tmplTodo, todo);

	var map = {'star' : todoRemoveStar, 'nostar' : todoAddStar};
	for (var k in map) {
		var btn = li.getElementsByClassName(k);
		if (btn.length > 0) {
			for (var i = 0; i < btn.length; ++ i) {
				btn[i].setAttribute('title', map[k]);
			}
		}
	}
}


////////////////////////////////////////////////////////////

function getTodoIndexFromElement(elem) {
	while(elem != document) {
		if (elem.tagName.toLowerCase() == 'li') {
			var children = elem.parentNode.children;
			for (var i = 0, l = children.length; i < l; ++ i) {
				if (children[i] == elem) {
					return i;
				}
			}
		}
		elem = elem.parentNode;
	}
	return -1;
}

function onTodoButtonDone(elem) {
	var index = getTodoIndexFromElement(elem);
	if (index != -1) {
		td.removeTodo(index);
	}
}

function onTodoButtonStar(elem) {
	var index = getTodoIndexFromElement(elem);
	if (index != -1) {
		var todo = td.getTodo(index);
		var priority = (todo.priority || 0);
		priority = (priority == 0) ? 1 : 0;
		td.changeTodo(index, todo.type, todo.text, priority);
	}
}


////////////////////////////////////////////////////////////
// event handlers

function onEvtTodoAdded(evt, index) {
	var todo = td.getTodo(index);
	if (todo != null) {
		insertTodo(todo);
	}
}

function onEvtTodoChanged(evt, index) {
	var list = $('todo-list');
	var lis = list.children;
	if (index >= 0 && index < lis.length) {
		var todo = td.getTodo(index);
		if (todo != null) {
			updateTodo(lis[index], todo);
		}
	}
}

function onEvtTodoRemoved(evt, index) {
	var list = $('todo-list');
	var lis = list.children;
	if (index >= 0 && index < lis.length) {
		var li = lis[index];
		list.removeChild(li);
	}
}

function onEvtTodoHide(evt, hide) {
	var panel = $('todo-panel');
	if (hide) {
		sU.addClass(panel, 'hide');
	} else {
		sU.removeClass(panel, 'hide');
	}
	var todoSwitch = $('todo-switch');
	todoSwitch.setAttribute('title', hide ? getString('ssTodoOpen') : getString('ssTodoClose'));
	layout();
}


var todoEventMap = {
	'todo-added': onEvtTodoAdded,
	'todo-changed': onEvtTodoChanged,
	'todo-removed': onEvtTodoRemoved,
	'todo-hide': onEvtTodoHide,
};

function registerTodoEvents() {
	try {
		for (var k in todoEventMap) {
			ob.subscribe(k, todoEventMap[k]);
		}
	} catch (e) {
		logger.logStringMessage('*** ' + e + ' ***');
	}
}

function unregisterTodoEvents() {
	try {
		for (var k in todoEventMap) {
			ob.unsubscribe(k, todoEventMap[k]);
		}
	} catch (e) {
		logger.logStringMessage('*** ' + e + ' ***');
	}
}


/////////////////////////////////////////////////////////////////////////////////////////
// utilities
function getMainWindow() {
	return window.QueryInterface(Ci.nsIInterfaceRequestor)
		.getInterface(Ci.nsIWebNavigation)
		.QueryInterface(Ci.nsIDocShellTreeItem)
		.rootTreeItem
		.QueryInterface(Ci.nsIInterfaceRequestor)
		.getInterface(Ci.nsIDOMWindow);
}

function $(id) {
	return document.getElementById(id);
}
